/**
 * 本地存储工具 SDK
 * 1. 可以在初始化的时候，就决定，你是要在本地存储，还是在其他地方存储，并且我能确定你是
 *  (localStorage, sessionStorage)
 *  - 所有的 API 都一样，只有初始化参数不一样。
 *
 * 2. 如果浏览器的存储，出现了异步的时序问题，高频的线程问题，我都可以解决；
 * 3. 如果本地缓存有问题，我在处理数据的时候，我是可以降级的
 * 4. 不用自己去解析，这个存储支持数组方法等。
 *
 * 加密、解密、过期时间。
 *
 */
const CreateStore = function (
  unlocal = false,
  opts = {
    maxLength: 30,
    expireTime: NaN,
  }
) {
  this.unlocal = unlocal;
  this.opts = opts;

  this.observe();
};

CreateStore.prototype.get = function (type) {
  return this.__proxy__storage[this.bizcode + '__' + type];
};

CreateStore.prototype.set = function (type, value) {
  this.__proxy__storage[this.bizcode + '__' + type] = value;
};

CreateStore.prototype.observe = function () {
  const context = this;

  this.__proxy__storage = new Proxy(
    {},
    {
      get: (target, key, receiver) => {
        if (!this.unlocal) {
          return context.getItem?.[key] || Reflect.get(target, key, receiver);
        }
        return Reflect.get(target, key, receiver);
      },
      set: (target, key, value, receiver) => {
        let _value = value;
        // 数据要劫持一下
        // 这里就是你核心业务层的代码
        if (value instanceof Array && value.length > context.maxLength) {
          _value.slice(0, maxLength);
        }

        if (context.expireTime) {
          // ...plugins
        }

        if (!this.unlocal) {
          context.setItem?.(key, _value);
        }

        return Reflect.set(target, key, _value, receiver);
      },
    }
  );
};

const methodArr = ['push', 'unshift', 'pop', 'reverse', 'splice', 'shift']
methodArr.forEach(method => {
  CreateStore.prototype[method] = function (type, ...args) {
    if(!this.get(type)) {
      this.set(type) = []
    }

    if(!this.get(type) instanceof Array) {
      throw new Error('must be array')
    }

    let context = this.get(type)
    Array.prototype[method].apply(context, ...args);
    this.set(type, context)
  };
});

CreateStore.prototype.getItem = function (key) {
  let data = window[this.storageMethod]?.getItem(key);
  let dataJson;
  try {
    dataJson = data && JSON.parse(data);
  } catch (error) {
    throw new Error(error)
  }
  return dataJson
};

CreateStore.prototype.setItem = function (key, value) {
  let dataStringfy = JSON.stringify(value)
  window[this.storageMethod]?.setItem(key, dataStringfy);
};

const CreateLocalStorage = function (bizcode, ...rest) {
  CreateStore.apply(this, rest)
  this.bizcode = bizcode
  this.storageMethod = "localStorage";
}

CreateLocalStorage.prototype = Object.create(CreateStore.prototype);
CreateLocalStorage.prototype.constructor = CreateLocalStorage;

const CreateSessionStorage = function (bizcode, ...rest) {
  CreateStore.apply(this, rest)
  this.bizcode = bizcode
  this.storageMethod = "sessionStorage";
}

CreateSessionStorage.prototype = Object.create(CreateStore.prototype);
CreateSessionStorage.prototype.constructor = CreateSessionStorage;

export const localStore = new CreateLocalStorage('kun')
export const sessionStore = new CreateSessionStorage('kun')